/* spi/spi.c
 *
 * SPI interface driver
 *
 * Copyright (c) 2011 by BKIT4U <www.bkit4u.com>
 * Author: BS135 <thanhhai135@gmail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General  Public  License
 * as published by the Free Software Foundation;version 2 or 2.1
 * of the License. This license can be found at
 *                           http://www.gnu.org/licenses/gpl.txt
 *
 * Target MCU	: Atmel AVR series
 * Editor Tabs	: 4
 */

#include <avr/io.h>
#include <stdint.h>
#include "spi.h"

/*
 * Initialization SPI I/O pins
 *
 * This function will set direction for MOSI, MISO, SCK pins.
 */
void spi_init_hardware(){
    spi_configure_pin_mosi();
    spi_configure_pin_sck();
    spi_configure_pin_miso();
}

/*
 * Initialization SPI operation mode at lowest speed
 */
void spi_init_low_mode(){
    SPCR = (0 << SPIE) | /* SPI Interrupt Enable */
           (1 << SPE)  | /* SPI Enable */
           (0 << DORD) | /* Data Order: MSB first */
           (1 << MSTR) | /* Master mode */
           (0 << CPOL) | /* Clock Polarity: SCK low when idle */
           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
           (1 << SPR1) | /* Clock Frequency: f_OSC / 128 */
           (1 << SPR0);
    SPSR &=~(1 << SPI2X);/* No doubled clock frequency */
}


/*
 * Initialization SPI operation mode at fastest speed
 */
void spi_init_fast_mode(){
    SPCR = (0 << SPIE) | /* SPI Interrupt Enable */
           (1 << SPE)  | /* SPI Enable */
           (0 << DORD) | /* Data Order: MSB first */
           (1 << MSTR) | /* Master mode */
           (0 << CPOL) | /* Clock Polarity: SCK low when idle */
           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
           (0 << SPR1) | /* Clock Frequency: f_OSC / 4 */
           (0 << SPR0);
    SPSR |= (1 << SPI2X);/* Doubled Clock Frequency: f_OSC / 2 */
}

/*
 * Initialization SPI operation mode at custom speed
 */
void spi_init_custom_mode(	uint8_t b_SPIE,
							uint8_t	b_SPE,
							uint8_t b_DORD,
							uint8_t b_MSTR,
							uint8_t b_CPOL,
							uint8_t b_CPHA,
							uint8_t b_SPR1,
							uint8_t b_SPR0,
							uint8_t b_SPI2X){
    SPCR = ((b_SPIE & 0x01) << SPIE) | 	/* SPI Interrupt Enable */
           ((b_SPE  & 0x01) << SPE)  | 	/* SPI Enable */
           ((b_DORD & 0x01) << DORD) | 	/* Data Order */
           ((b_MSTR & 0x01) << MSTR) | 	/* Master mode */
           ((b_CPOL & 0x01) << CPOL) | 	/* Clock Polarity */
           ((b_CPHA & 0x01) << CPHA) | 	/* Clock Phase */
           ((b_SPR1 & 0x01) << SPR1) | 	/* Clock Frequency */
           ((b_SPR0 & 0x01) << SPR0);
    SPSR &=~((b_SPI2X & 0x01) << SPI2X);/* No doubled clock frequency */
}

/*
 * Transmit a byte through SPI bus and get receive byte too.
 */
uint8_t spi_transfer(uint8_t b){
    SPDR = b;						/* start transmit byte */
    while(!(SPSR & (1 << SPIF)));	/* wait for byte to be shifted out */
    SPSR &= ~(1 << SPIF);			/* clear SPI interrupt flag */

    return SPDR;					/* return receive byte */
}

